using System;
using System.Collections;
using System.Collections.Generic;
using Godot;

/// <summary>
/// Ui 基类
/// </summary>
public abstract partial class UiBase : Control, IDestroy, ICoroutine
{
    /// <summary>
    /// Ui显示事件
    /// </summary>
    public event Action OnShowUiEvent;
    /// <summary>
    /// Ui隐藏事件
    /// </summary>
    public event Action OnHideUiEvent;
    /// <summary>
    /// Ui销毁事件
    /// </summary>
    public event Action OnDestroyUiEvent;
    
    /// <summary>
    /// 当前 UI 所属层级
    /// </summary>
    [Export]
    public UiLayer Layer = UiLayer.Middle;

    /// <summary>
    /// ui名称
    /// </summary>
    public string UiName { get; } 
    
    /// <summary>
    /// 是否已经打开ui
    /// </summary>
    public bool IsOpen { get; private set; } = false;

    public bool IsDestroyed { get; private set; }

    /// <summary>
    /// 负责记录上一个Ui
    /// </summary>
    public UiBase PrevUi { get; set; }

    /// <summary>
    /// 所属父级Ui, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
    /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
    /// </summary>
    public UiBase ParentUi { get; private set; }
    
    /// <summary>
    /// 所属父级节点, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
    /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
    /// </summary>
    public IUiNode ParentNode { get; private set; }

    /// <summary>
    /// 是否是嵌套的子 Ui
    /// </summary>
    public bool IsNestedUi => ParentUi != null;
    
    //开启的协程
    private List<CoroutineData> _coroutineList;
    //嵌套打开的Ui列表
    private HashSet<UiBase> _nestedUiSet;
    //嵌套模式下是否打开Ui
    private bool _nestedOpen;
    //当前Ui包含的 IUiNodeScript 接口, 关闭Ui是需要调用 IUiNodeScript.OnDestroy()
    private HashSet<IUiNodeScript> _nodeScripts;
    //存放事件集合的对象
    private EventFactory _eventFactory;
    //存放的IUiGrid对象
    private List<IUiGrid> _uiGrids;

    public UiBase(string uiName)
    {
        UiName = uiName;
        //记录ui打开
        UiManager.RecordUi(this, UiManager.RecordType.Open);
    }

    /// <summary>
    /// 创建当前ui时调用
    /// </summary>
    public virtual void OnCreateUi()
    {
    }
    
    /// <summary>
    /// 用于初始化打开的子Ui, 在 OnCreateUi() 之后调用
    /// </summary>
    public virtual void OnInitNestedUi()
    {
    }

    /// <summary>
    /// 当前ui显示时调用
    /// </summary>
    public virtual void OnShowUi()
    {
    }

    /// <summary>
    /// 当前ui隐藏时调用
    /// </summary>
    public virtual void OnHideUi()
    {
    }

    /// <summary>
    /// 销毁当前ui时调用
    /// </summary>
    public virtual void OnDestroyUi()
    {
    }

    /// <summary>
    /// 如果 Ui 处于打开状态, 则每帧调用一次
    /// </summary>
    public virtual void Process(float delta)
    {
    }

    /// <summary>
    /// 显示ui
    /// </summary>
    public void ShowUi()
    {
        if (IsDestroyed)
        {
            Debug.LogError($"当前Ui: {UiName}已经被销毁!");
            return;
        }
        
        Visible = true;
        if (IsOpen)
        {
            return;
        }

        _nestedOpen = true;
        IsOpen = true;
        OnShowUi();
        if (OnShowUiEvent != null)
        {
            OnShowUiEvent();
        }
        
        //子Ui调用显示
        if (_nestedUiSet != null)
        {
            foreach (var uiBase in _nestedUiSet)
            {
                if (uiBase._nestedOpen || uiBase.Visible)
                {
                    uiBase.ShowUi();
                }
            }
        }
    }
    
    /// <summary>
    /// 隐藏ui, 不会执行销毁
    /// </summary>
    public void HideUi()
    {
        if (IsDestroyed)
        {
            Debug.LogError($"当前Ui: {UiName}已经被销毁!");
            return;
        }

        Visible = false;
        if (!IsOpen)
        {
            return;
        }

        _nestedOpen = false;
        IsOpen = false;
        OnHideUi();
        if (OnHideUiEvent != null)
        {
            OnHideUiEvent();
        }
        
        //子Ui调用隐藏
        if (_nestedUiSet != null)
        {
            foreach (var uiBase in _nestedUiSet)
            {
                if (uiBase._nestedOpen)
                {
                    uiBase.HideUi();
                    uiBase._nestedOpen = true;
                }
            }
        }
    }

    /// <summary>
    /// 关闭并销毁ui
    /// </summary>
    public void Destroy()
    {
        if (IsDestroyed)
        {
            return;
        }
        //记录ui关闭
        UiManager.RecordUi(this, UiManager.RecordType.Close);
        HideUi();
        IsDestroyed = true;
        OnDestroyUi();
        if (OnDestroyUiEvent != null)
        {
            OnDestroyUiEvent();
        }

        if (_uiGrids != null)
        {
            foreach (var uiGrid in _uiGrids)
            {
                uiGrid.Destroy();
            }
            _uiGrids.Clear();
        }
        
        //子Ui调用销毁
        if (_nestedUiSet != null)
        {
            foreach (var uiBase in _nestedUiSet)
            {
                uiBase.ParentUi = null;
                uiBase.Destroy();
            }
            _nestedUiSet.Clear();
        }
        
        //销毁 IUiNodeScript
        if (_nodeScripts != null)
        {
            foreach (var uiNodeScript in _nodeScripts)
            {
                uiNodeScript.OnDestroy();
            }
        }

        //在父Ui中移除当前Ui
        if (ParentUi != null)
        {
            ParentUi.RecordNestedUi(this, null, UiManager.RecordType.Close);
        }

        RemoveAllEventListener();
        QueueFree();
    }

    /// <summary>
    /// 添加监听事件, 所有事件会在当前 ui 销毁时自动销毁
    /// </summary>
    /// <param name="eventType">事件类型</param>
    /// <param name="callback">回调函数</param>
    public void AddEventListener(EventEnum eventType, Action<object> callback)
    {
        if (_eventFactory == null)
        {
            _eventFactory = new EventFactory();
        }
        _eventFactory.AddEventListener(eventType, callback);
    }
    
    /// <summary>
    /// 移除所有的监听事件
    /// </summary>
    public void RemoveAllEventListener()
    {
        if (_eventFactory != null)
        {
            _eventFactory.RemoveAllEventListener();
        }
    }

    /// <summary>
    /// 创建一个UiGrid对象, 该Ui对象会在Ui销毁时自动销毁
    /// </summary>
    /// <param name="template">模板对象</param>
    /// <typeparam name="TNode">模板对象类型</typeparam>
    /// <typeparam name="TData">存放的数据类型</typeparam>
    /// <typeparam name="TCell">Cell处理类</typeparam>
    public UiGrid<TNode, TData> CreateUiGrid<TNode, TData, TCell>(TNode template) where TNode : IUiCellNode where TCell : UiCell<TNode, TData>
    {
        var uiGrid = new UiGrid<TNode, TData>(template, typeof(TCell));
        if (_uiGrids == null)
        {
            _uiGrids = new List<IUiGrid>();
        }
        _uiGrids.Add(uiGrid);
        return uiGrid;
    }

    /// <summary>
    /// 创建一个UiGrid对象, 该Ui对象会在Ui销毁时自动销毁
    /// </summary>
    /// <param name="template">模板对象</param>
    /// <param name="parent">父节点</param>
    /// <typeparam name="TNode">模板对象类型</typeparam>
    /// <typeparam name="TData">存放的数据类型</typeparam>
    /// <typeparam name="TCell">Cell处理类</typeparam>
    public UiGrid<TNode, TData> CreateUiGrid<TNode, TData, TCell>(TNode template, Node parent) where TNode : IUiCellNode where TCell : UiCell<TNode, TData>
    {
        var uiGrid = new UiGrid<TNode, TData>(template, parent, typeof(TCell));
        if (_uiGrids == null)
        {
            _uiGrids = new List<IUiGrid>();
        }
        _uiGrids.Add(uiGrid);
        return uiGrid;
    }
    
    public sealed override void _Process(double delta)
    {
        if (!IsOpen)
        {
            return;
        }
        var newDelta = (float)delta;
        Process(newDelta);
        
        //协程更新
        ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, newDelta);
    }

    /// <summary>
    /// 嵌套打开子ui
    /// </summary>
    public UiBase OpenNestedUi(string uiName, UiBase prevUi = null)
    {
        var packedScene = ResourceManager.Load<PackedScene>("res://" + GameConfig.UiPrefabDir + uiName + ".tscn");
        var uiBase = packedScene.Instantiate<UiBase>();
        uiBase.Visible = false;
        uiBase.PrevUi = prevUi;
        AddChild(uiBase);
        RecordNestedUi(uiBase, null, UiManager.RecordType.Open);
        
        uiBase.OnCreateUi();
        uiBase.OnInitNestedUi();
        if (IsOpen)
        {
            uiBase.ShowUi();
        }
        
        return uiBase;
    }

    /// <summary>
    /// 嵌套打开子ui
    /// </summary>
    public T OpenNestedUi<T>(string uiName, UiBase prevUi = null) where T : UiBase
    {
        return (T)OpenNestedUi(uiName, prevUi);
    }

    /// <summary>
    /// 记录嵌套打开/关闭的UI
    /// </summary>
    public void RecordNestedUi(UiBase uiBase, IUiNode node, UiManager.RecordType type)
    {
        if (type == UiManager.RecordType.Open)
        {
            if (uiBase.ParentUi != null && uiBase.ParentUi != this)
            {
                Debug.LogError($"子Ui:'{uiBase.UiName}'已经被其他Ui:'{uiBase.ParentUi.UiName}'嵌套打开!");
                uiBase.ParentUi.RecordNestedUi(uiBase, node, UiManager.RecordType.Close);
            }
            if (_nestedUiSet == null)
            {
                _nestedUiSet = new HashSet<UiBase>();
            }

            uiBase.ParentUi = this;
            uiBase.ParentNode = node;
            _nestedUiSet.Add(uiBase);
        }
        else
        {
            if (uiBase.ParentUi == this)
            {
                uiBase.ParentUi = null;
                uiBase.ParentNode = null;
            }
            else
            {
                Debug.LogError($"当前Ui:'{UiName}'没有嵌套打开子Ui:'{uiBase.UiName}'!");
                return;
            }
            
            if (_nestedUiSet == null)
            {
                return;
            }
            _nestedUiSet.Remove(uiBase);
        }
    }

    /// <summary>
    /// 记录当前Ui包含的 IUiNodeScript 接口
    /// </summary>
    public void RecordUiNodeScript(IUiNodeScript nodeScript)
    {
        if (_nodeScripts == null)
        {
            _nodeScripts = new HashSet<IUiNodeScript>();
        }
        _nodeScripts.Add(nodeScript);
    }

    /// <summary>
    /// 打开下一级Ui, 当前Ui会被隐藏
    /// </summary>
    /// <param name="uiName">下一级Ui的名称</param>
    public UiBase OpenNextUi(string uiName)
    {
        UiBase uiBase;
        if (ParentUi != null) //说明当前Ui是嵌套Ui
        {
            if (ParentNode != null) //子层级打开
            {
                uiBase = ParentNode.OpenNestedUi(uiName, this);
            }
            else
            {
                uiBase = ParentUi.OpenNestedUi(uiName, this);
            }
        }
        else //正常打开
        {
            uiBase = UiManager.OpenUi(uiName, this);
        }
        HideUi();
        return uiBase;
    }
    
    
    /// <summary>
    /// 打开下一级Ui, 当前Ui会被隐藏
    /// </summary>
    /// <param name="uiName">下一级Ui的名称</param>
    public T OpenNextUi<T>(string uiName) where T : UiBase
    {
        return (T)OpenNextUi(uiName);
    }

    /// <summary>
    /// 返回上一级Ui, 当前Ui会被销毁
    /// </summary>
    public void OpenPrevUi()
    {
        Destroy();
        if (PrevUi == null)
        {
            Debug.LogError($"Ui: {UiName} 没有记录上一级Ui!");
        }
        else
        {
            PrevUi.ShowUi();
        }
    }

    public long StartCoroutine(IEnumerator able)
    {
        return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
    }
    
    public void StopCoroutine(long coroutineId)
    {
        ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
    }
    
    public bool IsCoroutineOver(long coroutineId)
    {
        return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
    }
    
    public void StopAllCoroutine()
    {
        ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
    }
}